// [[ OnflowGenerator File UUID: 15986e320a2649a1ac457483f3488369  ]]
package com.itdct.onflow.system.task.manager

import com.itdct.onflow.core.extend.*
import com.itdct.onflow.core.util.TimeUtil
import com.itdct.onflow.system.common.base.BaseManager
import com.itdct.onflow.system.task.base.BaseTask
import com.itdct.onflow.system.task.constant.SysTaskCycleTypeConst
import com.itdct.onflow.system.task.constant.SysTaskExecuteStateConst
import com.itdct.onflow.system.task.entity.SysTaskEntity
import com.itdct.onflow.system.task.mapper.SysTaskMapper
import org.apache.commons.lang3.StringUtils
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler
import org.springframework.scheduling.support.CronTrigger
import org.springframework.stereotype.Component
import java.time.Duration
import java.util.*
import java.util.concurrent.ScheduledFuture

/**
 * @author DCTANT
 * @date 2025-09-19 16:39:00
 * @version 1.0
 * @description 定时任务中间层
 */
@Component
class SysTaskManager(
    val sysTaskMapper: SysTaskMapper,
    val taskScheduler: SimpleAsyncTaskScheduler,
    val redisTemplate: RedisTemplate<String, Any>
) : BaseManager() {

    private val taskIdFutureMap = HashMap<Long, List<ScheduledFuture<*>>>()

    fun runTask(taskId: Long) {
        val sysTaskEntity = sysTaskMapper.selectByIdEx(taskId, "无法找到该任务")
        sysTaskEntity.enable = true
        sysTaskEntity.executeState = SysTaskExecuteStateConst.NOT_START
        sysTaskMapper.updateEx(sysTaskEntity)
        runTask(sysTaskEntity)
    }

    fun runTask(sysTaskEntity: SysTaskEntity) {
        val id = sysTaskEntity.id ?: return
        val cycleType = sysTaskEntity.cycleType
        val taskClass = sysTaskEntity.taskClass
        val taskObj: BaseTask?
        try {
            taskObj = Class.forName(taskClass).getDeclaredConstructor().newInstance() as BaseTask
        } catch (e: Exception) {
            logError("类型转换失败", e)
            return
        }

        val firstDelayTime = sysTaskEntity.firstDelayTime
        val executeState = sysTaskEntity.executeState
        if (executeState == SysTaskExecuteStateConst.FINISH) {
            logInfo("任务ID：${sysTaskEntity.id}，名称：${sysTaskEntity.name}，已经完成，不加入执行队列")
            return
        }
        val enable = sysTaskEntity.enable
        if (!enable) {
            logInfo("任务ID：${sysTaskEntity.id}，名称：${sysTaskEntity.name}没有启用，跳过执行")
            return
        }
        val scheduledFutures = ArrayList<ScheduledFuture<*>>()
        taskIdFutureMap[id] = scheduledFutures

        when (cycleType) {
            SysTaskCycleTypeConst.SPECIFIC -> {
                val specifyTime = sysTaskEntity.specifyTime ?: throw RuntimeException("指定时间不能为空")
                if (StringUtils.isBlank(specifyTime)) {
                    return
                }
                val splitTime = specifyTime.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                val nowTime = System.currentTimeMillis()
                var scheduleCount = 0
                for (timeString in splitTime) {
                    val date = TimeUtil.timeStringToDate(timeString, TimeUtil.yyyyMMddHHmmss_HYPHEN) ?: continue
                    val time = date.time
                    if (time > nowTime) {
                        scheduleCount++
                        val schedule: ScheduledFuture<*> = taskScheduler.schedule({
                            if (firstDelayTime != null) {
                                try {
                                    Thread.sleep(firstDelayTime * 1000)
                                } catch (e: InterruptedException) {
                                    logError(e)
                                }
                            }
                            beforeRun(id)
                            taskObj.run(sysTaskEntity, redisTemplate)
                            afterRun(id)

                            val sysTaskEntityNow = sysTaskMapper.selectByIdEx(id)
                            sysTaskEntityNow.lastStartTime = Date()
                            // INFO: DCT: 2023/7/11 这个状态在run方法中算好了
                            sysTaskEntityNow.executeState = sysTaskEntity.executeState
                            sysTaskMapper.updateEx(sysTaskEntityNow)
                        }, date.toInstant())
                        scheduledFutures.add(schedule)
                    }
                }
                if (scheduleCount == 0) {
                    sysTaskEntity.executeState = SysTaskExecuteStateConst.FINISH
                    sysTaskMapper.updateEx(sysTaskEntity)
                }
            }

            SysTaskCycleTypeConst.CYCLE -> {
                val firstTime = sysTaskEntity.firstTime ?: throw RuntimeException("循环任务不存在首次执行时间")
                val intervalTime = sysTaskEntity.intervalTime ?: throw RuntimeException("循环任务不存在执行间隔时间")
                val schedule: ScheduledFuture<*> = taskScheduler.scheduleAtFixedRate({
                    beforeRun(id)
                    taskObj.run(sysTaskEntity, redisTemplate)
                    afterRun(id)
                }, firstTime.toInstant(), Duration.ofSeconds(intervalTime))
                scheduledFutures.add(schedule)
            }

            SysTaskCycleTypeConst.CRON -> {
                val cron = sysTaskEntity.cron ?: return
                if (StringUtils.isBlank(cron)) {
                    logWarn("cron表达式不存在")
                    return
                }
                try {
                    val schedule = taskScheduler.schedule({
                        beforeRun(id)
                        taskObj.run(sysTaskEntity, redisTemplate)
                        afterRun(id)
                    }, CronTrigger(cron))
                    if (schedule != null) {
                        scheduledFutures.add(schedule)
                    } else {
                        logWarn("下发任务失败！任务ID为：${id}")
                    }
                } catch (e: Exception) {
                    logError(e)
                    if (e is IllegalArgumentException) {
                        fail("cron表达式不正确")
                    } else {
                        fail(e.message ?: "系统出错，请稍后再试")
                    }
                }
            }
        }
    }

    fun beforeRun(taskId: Long) {
        try {
            // INFO: DCT: 2023/7/11 重查是为了保证实时性，防止出现这个sysTaskEntity已经被删了，或者已经被停了，但是又被更新为可执行状态
            val sysTaskEntity = sysTaskMapper.selectByIdEx(taskId)
            sysTaskEntity.executeState = SysTaskExecuteStateConst.RUNNING
            sysTaskEntity.lastStartTime = Date()
            var executeTimes = sysTaskEntity.executeTimes

            executeTimes += 1

            sysTaskEntity.executeTimes = executeTimes

            val firstTime = sysTaskEntity.firstTime
            if (firstTime == null) {
                sysTaskEntity.firstTime = Date()
            }
            sysTaskMapper.updateEx(sysTaskEntity)
        } catch (e: Exception) {
            logError("", e)
        }
    }

    fun afterRun(taskId: Long) {
        try {
            val sysTaskEntity = sysTaskMapper.selectByIdEx(taskId)
            sysTaskEntity.lastEndTime = Date()
            sysTaskEntity.executeState = SysTaskExecuteStateConst.WAITING
            sysTaskMapper.updateEx(sysTaskEntity)
        } catch (e: Exception) {
            logError("", e)
        }
    }

    fun stopTask(taskId: Long) {
        val scheduledFutures = taskIdFutureMap[taskId] ?: return
        for (scheduledFuture in scheduledFutures) {
            scheduledFuture.cancel(false)
        }
        try {
            val sysTaskEntity = sysTaskMapper.selectByIdEx(taskId)
            sysTaskEntity.enable = false
            sysTaskMapper.updateEx(sysTaskEntity)
        } catch (e: Exception) {
            logError("", e)
            return
        }
    }

    fun deleteTask(taskId: Long) {
        stopTask(taskId)

        sysTaskMapper.deleteByIdEx(taskId)
    }
}